package com.action.http;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * 
 * @author 北京八维博大科技 薛建新
 * @date 2022年11月10日 08:57:51
 * @Copyright 北京八维博大科技
 */
public class HttpClient {
	// multipart分隔符前缀
	private static final String BOUNDARY_PREFIX = "--";
	// multipart分隔符
	private static final String BOUNDARY = "----" + "HttpClientFormBoundary";
	// 换行
	private static final String NEW_LINE = "\r\n";

	private static final String REQUEST_LINE = "POST /j/upload HTTP/1.1"; // 请求行,必须
	private static final String HEADER_Host = "Host: %s:%s"; // 请求头Host,必须
	private static final String HEADER_ContentLength = "Content-Length: %d"; // 请求头Content-Length,必须
	private static final String HEADER_ContentType = "Content-Type: multipart/form-data; boundary=" + BOUNDARY; // 请求头Content-Type,必须

	private static final byte[] addFormData(String name, String value) {
		StringBuilder sb = new StringBuilder();
		sb.append(BOUNDARY_PREFIX);
		sb.append(BOUNDARY);
		sb.append(NEW_LINE);
		sb.append("Content-Disposition: form-data; name=\"").append(name).append("\"");
		sb.append(NEW_LINE);
		sb.append(NEW_LINE);
		sb.append(value);
		sb.append(NEW_LINE);
		byte[] bs = null;
		try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
			out.write(sb.toString().getBytes());
			bs = out.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bs;

	}

	private static final byte[] addFormFile(final InputStream is, String filename) {
		StringBuilder sb = new StringBuilder();
		sb.append(BOUNDARY_PREFIX);
		sb.append(BOUNDARY);
		sb.append(NEW_LINE);
		sb.append("Content-Disposition: form-data; name=\"").append("file").append("\"");
		//
		sb.append("; filename=\"").append(filename).append("\"");
		sb.append(NEW_LINE);
		sb.append("Content-Type: application/octet-stream");
		//
		sb.append(NEW_LINE);
		sb.append(NEW_LINE);
		byte[] bs = null;
		try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
			out.write(sb.toString().getBytes());
			out.write(is.readAllBytes());
			out.write((NEW_LINE + BOUNDARY_PREFIX + BOUNDARY).getBytes());
			bs = out.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bs;

	}

	private static byte[] httpRequest(String host, int port) {
		try (Socket client = new Socket(host, port)) {
			OutputStream os = client.getOutputStream();
			PrintWriter w = new PrintWriter(os);
			// 1. 写入请求行 requestLine
			w.write(REQUEST_LINE);
			w.write(NEW_LINE);

			// 2. 获取请求数据，并拼接 请求长度
			byte[] id = addFormData("id", "id1");
			byte[] name = addFormData("name", "name1");
			byte[] file = addFormFile(new FileInputStream("C:/Users/xueji/Desktop/图片像素.jpg"), "test1.jpg");
//			 byte[] file = addFormFile(new FileInputStream("C:/Users/xueji/Desktop/8025.sql"), "8025.sql");

			// 3. 写入请求header
			// host
			w.write(String.format(HEADER_Host, host, port));
			w.write(NEW_LINE);
			// contentlength，只是Body 长度，单位为字节，不算请求头，
			long contentLen = id.length + name.length + file.length;
			w.write(String.format(HEADER_ContentLength, contentLen));
			w.write(NEW_LINE);
			// contentType
			w.write(HEADER_ContentType);
			// 连续2个换行
			w.write(NEW_LINE);
			w.write(NEW_LINE);
			
			// 4.写入请求body
			w.flush();
			os.write(id);
			os.write(name);
			os.write(file);
			os.flush();

			client.shutdownOutput();
			return client.getInputStream().readAllBytes();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void main(String[] args) {
		// 服务端方法 demo20220728/src/main/java/com/action/TestController.java#upload
		System.out.println(new String(httpRequest("localhost", 18082)));
	}

}
